﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of RinexFileReader.                                       **
**                                                                              **
**  RinexFileReader is free software: you can redistribute it and/or modify     **
**  it under the terms of the GNU General Public License as published by        **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  RinexFileReader is distributed in the hope that it will be useful,          **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU General Public License for more details.                                **
**                                                                              **
**  You should have received a copy of the GNU General Public License           **
**  along with RinexFileReader. If not, see <https://www.gnu.org/licenses/>.    **
**********************************************************************************/

#pragma once

#include "RinexFile.h"

#include <format>
#include <ranges>

template<typename T>
struct std::formatter<std::vector<T>> : public std::formatter<std::string_view>
{
    auto format(const std::vector<T>& t, std::format_context& fc) const
    {
        std::string str;
        str.push_back('[');
        for (const auto& val : t)
        {
            if (str.size() != 1)
                str.push_back(',');
            std::format_to(std::back_inserter(str), "{}", val);
        }
        str.push_back(']');
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<typename T>
struct std::formatter<std::optional<T>> : public std::formatter<std::string_view>
{
    auto format(const std::optional<T>& t, std::format_context& fc) const
    {
        std::string str;
        if (t)
            std::format_to(std::back_inserter(str), "{}", *t);
        else
            str = "null";
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::SatelliteSystem> : public std::formatter<std::string_view>
{
    constexpr static auto satelliteSystems = { "GPS", "GLONASS", "Galileo", "QZSS", "BDS", "NavIC", "SBASPayload", "Mixed" };
    auto format(const Rinex::SatelliteSystem& t, std::format_context& fc) const
    {
        auto str = (*(satelliteSystems.begin() + static_cast<int>(t)));
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::SystemTimeIdentifier> : public std::formatter<std::string_view>
{
    constexpr static auto systemTimeIdentifier = { "GPS", "GLONASS", "Galileo", "QZSS", "BDS", "NavIC" };
    auto format(const Rinex::SystemTimeIdentifier& t, std::format_context& fc) const
    {
        auto str = (*(systemTimeIdentifier.begin() + static_cast<int>(t)));
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::CorrectionType> : public std::formatter<std::string_view>
{
    constexpr static auto correctionType = { "GAL", "GPSA", "GPSB", "QZSA", "QZSB", "BDSA", "BDSB", "IRNA", "IRNB" };
    auto format(const Rinex::CorrectionType& t, std::format_context& fc) const
    {
        auto str = (*(correctionType.begin() + static_cast<int>(t)));
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::TimeSystemCorrType> : public std::formatter<std::string_view>
{
    constexpr static auto timeSystemCorrType = { "GPUT", "GLUT", "GAUT", "BDUT", "QZUT", "IRUT", "SBUT", "GLGP", "GAGP", "QZGP", "IRGP" };
    auto format(const Rinex::TimeSystemCorrType& t, std::format_context& fc) const
    {
        auto str = (*(timeSystemCorrType.begin() + static_cast<int>(t)));
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::ObservationType> : public std::formatter<std::string_view>
{
    constexpr static auto observationType = {
        "Pressure",    "DryTemperature", "RelativeHumidity", "WetZenithPathDelay", "DryComponentOfZenPathDelay", "TotalZenithPathDelay",
        "WindAzimuth", "WindSpeed",      "RainIncrement",    "HailIndicator"
    };
    auto format(const Rinex::ObservationType& t, std::format_context& fc) const
    {
        auto str = (*(observationType.begin() + static_cast<int>(t)));
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::DateTime> : public std::formatter<std::string_view>
{
    auto format(const Rinex::DateTime& t, std::format_context& fc) const
    {
        auto str =
            std::format("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}", t.year, t.month, t.day, t.hour, t.minute, t.second, t.msec);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::PhaseCenter> : public std::formatter<std::string_view>
{
    auto format(const Rinex::PhaseCenter& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{}", t.satelliteSystem, t.observationCode, t.northEastUpOrXYZ);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::SysObsTypes> : public std::formatter<std::string_view>
{
    auto format(const Rinex::SysObsTypes& t, std::format_context& fc) const
    {
        auto str = std::format("{},{}", t.satelliteSystem, t.types);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::TimeOfObs> : public std::formatter<std::string_view>
{
    auto format(const Rinex::TimeOfObs& t, std::format_context& fc) const
    {
        auto str = std::format("{},{}", t.time, t.systemTime);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::GLONASSSlotFreq> : public std::formatter<std::string_view>
{
    auto format(const Rinex::GLONASSSlotFreq& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{}", t.systemCode, t.slot_, t.frequencyNumber);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::LeapSeconds> : public std::formatter<std::string_view>
{
    auto format(const Rinex::LeapSeconds& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{},{},{}", t.currentNumber, t.deltaTLSF, t.wnLSF, t.respectiveDayNumber, t.systemTimeIdentifier);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::PrnOfObs> : public std::formatter<std::string_view>
{
    auto format(const Rinex::PrnOfObs& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{}", t.satelliteSystem, t.id, t.records);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<std::vector<Rinex::PrnOfObs>> : public std::formatter<std::string_view>
{
    auto format(const std::vector<Rinex::PrnOfObs>& t, std::format_context& fc) const
    {
        std::string str;
        str.push_back('[');
        for (const auto& val : t)
        {
            if (str.size() != 1)
                str.append(",\n");
            std::format_to(std::back_inserter(str), "{}", val);
        }
        str.push_back(']');
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::ObsRecords::Record> : public std::formatter<std::string_view>
{
    auto format(const Rinex::ObsRecords::Record& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{}", t.record, t.lli, t.ssi);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::ObsRecords> : public std::formatter<std::string_view>
{
    auto format(const Rinex::ObsRecords& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{}", t.satelliteSystem, t.id, t.records);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::ObsData> : public std::formatter<std::string_view>
{
    auto format(const Rinex::ObsData& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{},{},{}", t.epoch, t.epochFlag, t.numberOfSatellites, t.receiverClockOffsetCorrection, t.records);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<std::vector<Rinex::ObsData>> : public std::formatter<std::string_view>
{
    auto format(const std::vector<Rinex::ObsData>& t, std::format_context& fc) const
    {
        std::string str;
        str.push_back('[');
        for (const auto& val : t)
        {
            if (str.size() != 1)
                str.append(",\n");
            std::format_to(std::back_inserter(str), "{}", val);
        }
        str.push_back(']');
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::IonosphericCorr> : public std::formatter<std::string_view>
{
    auto format(const Rinex::IonosphericCorr& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{},{}", t.correctionType, t.parameters, t.timeMark, t.svID);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<std::vector<Rinex::IonosphericCorr>> : public std::formatter<std::string_view>
{
    auto format(const std::vector<Rinex::IonosphericCorr>& t, std::format_context& fc) const
    {
        std::string str;
        str.push_back('[');
        for (const auto& val : t)
        {
            if (str.size() != 1)
                str.append(",\n");
            std::format_to(std::back_inserter(str), "{}", val);
        }
        str.push_back(']');
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::TimeSystemCorr> : public std::formatter<std::string_view>
{
    auto format(const Rinex::TimeSystemCorr& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{},{},{},{},{}", t.type, t.a0, t.a1, t.t, t.w, t.satelliteID, t.utcIdentifier);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<std::vector<Rinex::TimeSystemCorr>> : public std::formatter<std::string_view>
{
    auto format(const std::vector<Rinex::TimeSystemCorr>& t, std::format_context& fc) const
    {
        std::string str;
        str.push_back('[');
        for (const auto& val : t)
        {
            if (str.size() != 1)
                str.append(",\n");
            std::format_to(std::back_inserter(str), "{}", val);
        }
        str.push_back(']');
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::NMData> : public std::formatter<std::string_view>
{
    auto format(const Rinex::NMData& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{},{}", t.satelliteSystem, t.id, t.epoch, t.datas);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<std::vector<Rinex::NMData>> : public std::formatter<std::string_view>
{
    auto format(const std::vector<Rinex::NMData>& t, std::format_context& fc) const
    {
        std::string str;
        str.push_back('[');
        for (const auto& val : t)
        {
            if (str.size() != 1)
                str.append(",\n");
            std::format_to(std::back_inserter(str), "{}", val);
        }
        str.push_back(']');
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::SensorModTypeAcc> : public std::formatter<std::string_view>
{
    auto format(const Rinex::SensorModTypeAcc& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{},{}", t.model, t.type, t.accuracy, t.obsType);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::SensorPosXYZH> : public std::formatter<std::string_view>
{
    auto format(const Rinex::SensorPosXYZH& t, std::format_context& fc) const
    {
        auto str = std::format("{},{},{},{},{}", t.x, t.y, t.z, t.h, t.type);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::MetData> : public std::formatter<std::string_view>
{
    auto format(const Rinex::MetData& t, std::format_context& fc) const
    {
        auto str = std::format("{},{}", t.dateTime, t.datas);
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<std::vector<Rinex::MetData>> : public std::formatter<std::string_view>
{
    auto format(const std::vector<Rinex::MetData>& t, std::format_context& fc) const
    {
        std::string str;
        str.push_back('[');
        for (const auto& val : t)
        {
            if (str.size() != 1)
                str.append(",\n");
            std::format_to(std::back_inserter(str), "{}", val);
        }
        str.push_back(']');
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::ObservationDataFile> : public std::formatter<std::string_view>
{
    auto format(const Rinex::ObservationDataFile& t, std::format_context& fc) const
    {
        std::string str;
        auto it = std::back_inserter(str);
        std::format_to(it, "---------------------------------ObservationDataFile--------------------------------\n");
        std::format_to(it, "IONEX VERSION / TYPE\n");
        std::format_to(it, "Version:{}\nSatelliteSystem:{}\n", t.version(), t.satelliteSystem());
        std::format_to(it, "PGM / RUN BY / DATE\n");
        std::format_to(it, "Program:{}\nAgency:{}\nCreateDateTime:{}\n", t.program(), t.agency(), t.createDateTime());
        std::format_to(it, "COMMENT\n");
        for (const auto& str : t.comments())
            std::format_to(it, "{}\n", str);
        std::format_to(it, "MARKER NAME\n");
        std::format_to(it, "{}\n", t.markerName());
        std::format_to(it, "MARKER NUMBER\n");
        std::format_to(it, "{}\n", t.markerNumber());
        std::format_to(it, "MARKER TYPE\n");
        std::format_to(it, "{}\n", t.markerType());
        std::format_to(it, "OBSERVER / AGENCY\n");
        std::format_to(it, "{}\n", t.observerAgency());
        std::format_to(it, "REC # / TYPE / VERS\n");
        std::format_to(it, "RecNumber:{}\nRecType:{}\nRecVersion:{}\n", t.recNumber(), t.recType(), t.recVersion());
        std::format_to(it, "ANT # / TYPE\n");
        std::format_to(it, "AntNumber:{}\nAntType:{}\n", t.antNumber(), t.antType());
        std::format_to(it, "APPROX POSITION XYZ\n");
        std::format_to(it, "{}\n", t.approxPositionXYZ());
        std::format_to(it, "ANTENNA: DELTA H/E/N\n");
        std::format_to(it, "{}\n", t.antennaDeltaHEN());
        std::format_to(it, "ANTENNA: DELTA X/Y/Z\n");
        std::format_to(it, "{}\n", t.antennaDeltaXYZ());
        std::format_to(it, "ANTENNA: PHASECENTER\n");
        std::format_to(it, "{}\n", t.phaseCenter());
        std::format_to(it, "ANTENNA: B.SIGHT XYZ\n");
        std::format_to(it, "{}\n", t.antennaBSightXYZ());
        std::format_to(it, "ANTENNA: ZERODIR AZI\n");
        std::format_to(it, "{}\n", t.antennaZerodirAZI());
        std::format_to(it, "ANTENNA: ZERODIR XYZ\n");
        std::format_to(it, "{}\n", t.antennaZerodirXYZ());
        std::format_to(it, "CENTER OF MASS: XYZ\n");
        std::format_to(it, "{}\n", t.centerOfMassXYZ());
        std::format_to(it, "DOI\n");
        std::format_to(it, "{}\n", t.doi());
        std::format_to(it, "LICENSE OF USE\n");
        std::format_to(it, "{}\n", t.licenseOfUse());
        std::format_to(it, "STATION INFORMATION\n");
        std::format_to(it, "{}\n", t.stationInformation());
        std::format_to(it, "SYS / # / OBS TYPES\n");
        std::format_to(it, "{}\n", t.sysObsTypes());
        std::format_to(it, "SIGNAL STRENGTH UNIT\n");
        std::format_to(it, "{}\n", t.signalStrengthUnit());
        std::format_to(it, "INTERVAL\n");
        std::format_to(it, "{}\n", t.interval());
        std::format_to(it, "TIME OF FIRST OBS\n");
        std::format_to(it, "{}\n", t.timeOfFirstObs());
        std::format_to(it, "TIME OF LAST OBS\n");
        std::format_to(it, "{}\n", t.timeOfLastObs());
        std::format_to(it, "GLONASS SLOT / FRQ #\n");
        std::format_to(it, "{}\n", t.glonassSlotFreq());
        std::format_to(it, "LEAP SECONDS\n");
        std::format_to(it, "{}\n", t.leapSeconds());
        std::format_to(it, "# OF SATELLITES\n");
        std::format_to(it, "{}\n", t.ofSatellites());
        std::format_to(it, "PRN / # OF OBS\n");
        std::format_to(it, "{}\n", t.prnOfObs());
        std::format_to(it, "--------------Datas--------------\n");
        std::format_to(it, "{}\n", t.datas());
        std::format_to(it, "--------------------------END--------------------------\n");
        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::NavigationMessageFile> : public std::formatter<std::string_view>
{
    auto format(const Rinex::NavigationMessageFile& t, std::format_context& fc) const
    {
        std::string str;
        auto it = std::back_inserter(str);
        std::format_to(it, "----------------------NavigationMessageFile-----------------------\n");
        std::format_to(it, "IONEX VERSION / TYPE\n");
        std::format_to(it, "Version:{}\nSatelliteSystem:{}\n", t.version(), t.satelliteSystem());
        std::format_to(it, "PGM / RUN BY / DATE\n");
        std::format_to(it, "Program:{}\nAgency:{}\nCreateDateTime:{}\n", t.program(), t.agency(), t.createDateTime());
        std::format_to(it, "REC # / TYPE / VERS\n");
        std::format_to(it, "RecNumber:{}\nRecType:{}\nRecVersion:{}\n", t.recNumber(), t.recType(), t.recVersion());
        std::format_to(it, "COMMENT\n");
        for (const auto& str : t.comments())
            std::format_to(it, "{}\n", str);
        std::format_to(it, "IONOSPHERIC CORR\n");
        std::format_to(it, "{}\n", t.ionosphericCorrs());
        std::format_to(it, "TIME SYSTEM CORR\n");
        std::format_to(it, "{}\n", t.timeSystemCorrs());
        std::format_to(it, "MERGED FILE\n");
        std::format_to(it, "{}\n", t.mergedFile());
        std::format_to(it, "DOI\n");
        std::format_to(it, "{}\n", t.doi());
        std::format_to(it, "LICENSE OF USE\n");
        std::format_to(it, "{}\n", t.licenseOfUse());
        std::format_to(it, "STATION INFORMATION\n");
        std::format_to(it, "{}\n", t.stationInformation());
        std::format_to(it, "LEAP SECONDS\n");
        std::format_to(it, "{}\n", t.leapSeconds());
        std::format_to(it, "--------------Datas--------------\n");
        std::format_to(it, "{}\n", t.datas());
        std::format_to(it, "--------------------------END--------------------------\n");

        return std::formatter<std::string_view>::format(str, fc);
    }
};

template<>
struct std::formatter<Rinex::MeteorologicalDataFile> : public std::formatter<std::string_view>
{
    auto format(const Rinex::MeteorologicalDataFile& t, std::format_context& fc) const
    {
        std::string str;
        auto it = std::back_inserter(str);
        std::format_to(it, "----------------------MeteorologicalDataFile-----------------------\n");
        std::format_to(it, "IONEX VERSION / TYPE\n");
        std::format_to(it, "Version:{}\n", t.version());
        std::format_to(it, "PGM / RUN BY / DATE\n");
        std::format_to(it, "Program:{}\nAgency:{}\nCreateDateTime:{}\n", t.program(), t.agency(), t.createDateTime());
        std::format_to(it, "COMMENT\n");
        for (const auto& str : t.comments())
            std::format_to(it, "{}\n", str);
        std::format_to(it, "MARKER NAME\n");
        std::format_to(it, "{}\n", t.markerName());
        std::format_to(it, "MARKER NUMBER\n");
        std::format_to(it, "{}\n", t.markerNumber());
        std::format_to(it, "# / TYPES OF OBSERV\n");
        std::format_to(it, "{}\n", t.observationTypes());
        std::format_to(it, "SENSOR MOD/TYPE/ACC\n");
        std::format_to(it, "{}\n", t.sensorModTypeAcc());
        std::format_to(it, "SENSOR POS XYZ/H\n");
        std::format_to(it, "{}\n", t.sensorPosXYZH());
        std::format_to(it, "--------------Datas--------------\n");
        std::format_to(it, "{}\n", t.datas());
        std::format_to(it, "--------------------------END--------------------------\n");

        return std::formatter<std::string_view>::format(str, fc);
    }
};